package com.cby.code.net.task;


import com.cby.code.net.Method;
import com.cby.code.net.Request;
import com.cby.code.net.RequestParam;
import com.cby.code.net.Response;
import com.cby.code.net.ssl.HttpsHostnameVerifier;
import com.cby.code.net.ssl.HttpsSSLSocketFactory;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

import javax.net.ssl.HttpsURLConnection;

/**
 * @description: 网络任务基类
 * @author: ChenBaoYang
 * @createDate: 2022/2/14 5:24 下午
 */
public abstract class BaseTask {

    /** 请求的header属性 */
    protected static final String REQ_PROPERTY_CONNECTION = "Connection";
    protected static final String REQ_VALUE_CONNECTION = "Keep-Alive";

    /**
     * utf-8字符集
     */
    protected static final String CHARSET_UTF8 = "UTF-8";

    /**
     * 连接超时时间，7秒
     */
    protected static final int CONNECT_TIMEOUT = 7 * 1000;

    /**
     * 读取超时时间
     */
    protected static final int READ_TIMEOUT = 7 * 1000;


    /**
     * 创建网络连接对象
     *
     * @param request
     * @return
     * @throws IOException
     */
    protected HttpURLConnection createConnection(Request request) throws IOException {
        String baseUrl = request.getUrl();
        String pathSegment = request.getPathSegment();
        if (pathSegment != null && pathSegment.length() > 0) {
            baseUrl += pathSegment;
        }
        if(request.getMethod() == Method.GET) {

            String url = baseUrl + request.getParam().convertToPathParamString();
            return openURLConnection(url);
        }else {
            return openURLConnection(baseUrl);
        }
    }

    /**
     * 创建并打开一个连接
     * @param baseUrl
     * @return
     * @throws IOException
     */
    protected HttpURLConnection openURLConnection(String baseUrl)
            throws IOException {
        URL url = new URL(baseUrl);
        HttpURLConnection urlConnection = (HttpURLConnection)url.openConnection();
        //添加https的认证
        if (baseUrl.toUpperCase().startsWith("HTTPS")) {
            HttpsURLConnection httpsURLConnection = (HttpsURLConnection) urlConnection;
            httpsURLConnection.setHostnameVerifier(new HttpsHostnameVerifier());
            httpsURLConnection.setSSLSocketFactory(HttpsSSLSocketFactory.factory());
            urlConnection = httpsURLConnection;
        }
        // Workaround for the M release HttpURLConnection not observing the
        // HttpURLConnection.setFollowRedirects() property.
        // https://code.google.com/p/android/issues/detail?id=194495
        urlConnection.setInstanceFollowRedirects(HttpURLConnection.getFollowRedirects());
        //urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");

        //设置超时时间
        urlConnection.setConnectTimeout(CONNECT_TIMEOUT);
        urlConnection.setReadTimeout(READ_TIMEOUT);

        //设置连接类型
        urlConnection.setRequestProperty(REQ_PROPERTY_CONNECTION, REQ_VALUE_CONNECTION);

        //不使用缓存
        urlConnection.setUseCaches(false);

        //设置输入
        urlConnection.setDoInput(true);

        return urlConnection;
    }

    /**
     * 设置请求的参数和方式
     * @param connection
     * @param request
     * @throws Exception
     */
    public void setConnectionParametersForRequest(
            HttpURLConnection connection, Request request) throws Exception {
        switch (request.getMethod()) {
            case Method.GET:
                connection.setRequestMethod("GET");
                break;
            case Method.DELETE:
                connection.setRequestMethod("DELETE");
                break;
            case Method.POST:
                connection.setRequestMethod("POST");
                addBody(connection, request.getParam());
                break;
            case Method.PUT:
                connection.setRequestMethod("PUT");
                addBody(connection, request.getParam());
                break;
            case Method.HEAD:
                connection.setRequestMethod("HEAD");
                break;
            case Method.OPTIONS:
                connection.setRequestMethod("OPTIONS");
                break;
            case Method.TRACE:
                connection.setRequestMethod("TRACE");
                break;
            default:
                throw new IllegalStateException("Unknown method type.");
        }
    }

    /**
     * 设置请求头
     * @param connection
     * @param requestParam
     */
    public void setHeaders(HttpURLConnection connection, RequestParam requestParam) {
        if(requestParam != null ) {
            requestParam.putHeaders(connection);
        }
    }

    /**
     * 设置请求体
     * @param urlConnection
     * @param requestParam
     * @throws IOException
     */
    public void addBody(HttpURLConnection urlConnection, RequestParam requestParam) throws IOException {
        //设置输出
        urlConnection.setDoOutput(true);
        String newParams = requestParam.convertParamString();
        //参数写入
        DataOutputStream outputStream = new DataOutputStream(
                urlConnection.getOutputStream()
        );
        outputStream.write(newParams.getBytes());
        outputStream.flush();
        outputStream.close();
    }

    /**
     * 关闭连接
     * @param connection
     */
    protected void closeConnection(HttpURLConnection connection) {
        if (null != connection) {
            connection.disconnect();
        }
    }

    /**
     * 流转换为string字符串
     * @param inputStream
     * @return
     * @throws IOException
     */
    protected String streamToString(InputStream inputStream)
            throws IOException {

        BufferedReader br = new BufferedReader(new InputStreamReader(inputStream,
                CHARSET_UTF8));

        StringBuffer sb = new StringBuffer();

        String line;

        while ((line = br.readLine()) != null) {
            sb.append(line);
        }

        br.close();

        return sb.toString();

    }




    /**
     * 网络请求是否成功
     */
    protected boolean isOK(int responseCode) {
        return responseCode == HttpURLConnection.HTTP_OK;
    }

    /**
     * 执行请求的流程的抽象方法
     * @param request
     * @return
     */
    public abstract Response performRequest(Request request);
}
